/*
 *
 * Copyright (C) 2012 Mauricio Garcia
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "msocket.h"
#include <string.h>
#include <signal.h>

extern char connectKey[64];
extern int connectKeyLen;
extern char disconnectKey[64];
extern int disconnectKeyLen;
extern char establishedKey[64];
extern int establishedKeyLen;
extern char unestablishedKey[64];
extern int unestablishedKeyLen;

int pid = -1;

// Handler of the keyboard interruption signal
void intHandler(int sig){
	if(pid > 0){
  	printf("Sending signal to the child, pid %i\n",pid);
		kill(pid,SIGTERM);
	}
  printf("Exiting\n");
  exit(0);
}

int main(int argc, char *argv[]){

  if(argc != 4){
    printf("Parameters: ip port id\n");
    exit(1);
  }

  signal(SIGINT,intHandler);
   
  struct sockaddr_in peerSockAddr,peerSockAddrOther;
  int socketPeer, socketPeerOther = -1, socketPeerTmp;
  int ntransp;
  char id[32];
  strcpy(id,argv[3]);
  int localStreamPort = 5555;

  // Configure the client
  peerSockAddr.sin_family = AF_INET;
  peerSockAddr.sin_addr.s_addr = inet_addr(argv[1]);
  peerSockAddr.sin_port = htons(atoi(argv[2]));
  socketPeer = Socket( AF_INET, SOCK_STREAM, 0 );
  
  // Connect to the server  
  printf("Trying to conect to %s:%i\n",inet_ntoa(peerSockAddr.sin_addr),
					ntohs(peerSockAddr.sin_port));
  Connect(socketPeer,(struct sockaddr*)&peerSockAddr,sizeof(peerSockAddr)); 
  
  // Send the id
  ntransp = Send( socketPeer,id,strlen(id)+1, 0 );
  printf("Connected\n");
  
  struct timeval timeout;
  timeout.tv_sec = 1;
  timeout.tv_usec = 0;
  
  fd_set socksSetRead;
  char bufferMsg[256];
  char connectedMsg[32];
  char peerID[32];
  int i,j;

  // Main loop of the client
  while(1){
    
    // Initialize the sockets set
    FD_ZERO(&socksSetRead);
    FD_SET(socketPeer,&socksSetRead);  
    FD_SET(0,&socksSetRead);  
    
    if(select(socketPeer+1,&socksSetRead,NULL,NULL,&timeout) < 0){
      perror("Select error:");
    }
    
    if(FD_ISSET(0,&socksSetRead)){ // If stdin is ready
      gets(bufferMsg);
      // Connection
      if(memcmp(bufferMsg,establishedKey,establishedKeyLen) == 0){
				if(socketPeerOther == -1){
					socketPeerTmp = atoi(&bufferMsg[establishedKeyLen]);
					memcpy(&bufferMsg[establishedKeyLen],&socketPeerTmp,sizeof(int));
					ntransp = Send(socketPeer,bufferMsg,establishedKeyLen + sizeof(int), 0 );
				}else{
				  printf("You have a established connection with %s\n",peerID);
				}
      }else if(memcmp(bufferMsg,unestablishedKey,unestablishedKeyLen) == 0){
				// Disconnection
				ntransp = Send(socketPeer,bufferMsg,unestablishedKeyLen, 0 );
      }else{ // Normal message
				ntransp = Send(socketPeer,bufferMsg,strlen(bufferMsg), 0 );
      }
    }
    
    if(FD_ISSET(socketPeer,&socksSetRead)){ // If socketPeer is ready
      ntransp = Recv(socketPeer,bufferMsg,sizeof(bufferMsg),0);
      if(ntransp <= 0){
				if(ntransp<0){
				  perror("Receive error");
				  exit(1);
				}else{
				  printf("Served dead\n");
	  			exit(0);
				}
      }
      bufferMsg[ntransp] = '\0';
      // Another peer connected
      if(memcmp(bufferMsg,connectKey,connectKeyLen) == 0){
				for(i=1,j=0; i<=ntransp; i++){
	  			if(memcmp(&bufferMsg[i],connectKey,connectKeyLen) == 0 || i==ntransp){
				    memcpy(&socketPeerTmp,&bufferMsg[j+connectKeyLen],sizeof(int));
				    memcpy(connectedMsg,&bufferMsg[j+connectKeyLen+sizeof(int)],i-j-sizeof(int));
	    			connectedMsg[i-j-sizeof(int)-connectKeyLen] = '\0';
	    			printf("Connected: %i %s\n",socketPeerTmp,connectedMsg);
	    			j=i;
	  			}
				}
      }else if(memcmp(bufferMsg,disconnectKey,disconnectKeyLen) == 0){
				// Another peer disconnected
				printf("Disconnected: %s\n",&bufferMsg[disconnectKeyLen+sizeof(int)]);
				memcpy(&socketPeerTmp,&bufferMsg[connectKeyLen],sizeof(int));
				if(socketPeerTmp == socketPeerOther){
	  			socketPeerOther = -1;
					if(pid > 0){
				  	printf("Sending signal to the child, pid %i\n",pid);
						kill(pid,SIGTERM);
						pid = -1;
					}
				}
      }else if(memcmp(bufferMsg,establishedKey,establishedKeyLen) == 0){
				// Connection established
				memcpy(&socketPeerOther,&bufferMsg[establishedKeyLen],sizeof(int));
				memcpy(&peerSockAddrOther,&bufferMsg[establishedKeyLen+sizeof(int)],
								sizeof(peerSockAddrOther));
				memcpy(peerID,&bufferMsg[establishedKeyLen+sizeof(int)+sizeof(peerSockAddrOther)],
	      ntransp-establishedKeyLen-sizeof(int)-sizeof(peerSockAddrOther));
				peerID[ntransp-establishedKeyLen-sizeof(int)-sizeof(peerSockAddrOther)] = '\0';
				printf("Established with %s\n",peerID);
				printf("From: %s:%i\n",inet_ntoa(peerSockAddrOther.sin_addr),
				ntohs(peerSockAddrOther.sin_port));		

				// Make the fork
				pid = fork();

				if(pid < 0)
					perror("Error in fork");
	
				if(pid){// In the parent 
					//waitpid(pid);
				}else{
					// In the child
		  		close(socketPeer);
					// Create a new session and detach its controling terminal 
					setsid();
					// 
					playStream(localStreamPort,
					inet_ntoa(peerSockAddrOther.sin_addr), localStreamPort);
  			  exit(0);
				}
      }else if(memcmp(bufferMsg,unestablishedKey,unestablishedKeyLen) == 0){
				// Connection unestablished
				socketPeerOther = -1;
				printf("Unestablished connection with %s\n",&bufferMsg[unestablishedKeyLen]);
				if(pid > 0){
			  	printf("Sending signal to the child, pid %i\n",pid);
					kill(pid,SIGTERM);
					pid = -1;
				}
      }else{
				printf("%s says: %s\n",peerID,bufferMsg);
      }
    }
  }
  
  return 0;
}




